package logger

import (
	"os"

	"gitee.com/hexug/devcloud/maudit/conf"
	"go.uber.org/zap"
	"go.uber.org/zap/zapcore"
	"gopkg.in/natefinch/lumberjack.v2"
)

// 正常日志编码器
func GetFileEnCoder() zapcore.Encoder {
	config := zap.NewProductionEncoderConfig()
	config.EncodeTime = zapcore.ISO8601TimeEncoder
	config.EncodeLevel = zapcore.CapitalLevelEncoder
	config.EncodeDuration = zapcore.NanosDurationEncoder
	config.EncodeCaller = zapcore.ShortCallerEncoder
	config.EncodeName = zapcore.FullNameEncoder
	return zapcore.NewConsoleEncoder(config)
}

// 带颜色的日志编码器
func GetConsoleEnCoder() zapcore.Encoder {
	config := zap.NewProductionEncoderConfig()
	config.EncodeTime = zapcore.ISO8601TimeEncoder
	config.EncodeLevel = zapcore.CapitalColorLevelEncoder
	config.EncodeCaller = zapcore.ShortCallerEncoder
	return zapcore.NewConsoleEncoder(config)
}

// 生成普通信息的Writer
func GetInfoWriterSyncer(dir string) zapcore.WriteSyncer {
	//引入第三方库 Lumberjack 加入日志切割功能
	infoLumberIO := &lumberjack.Logger{
		Filename:   dir + "/info.log",
		MaxSize:    10, // megabytes
		MaxBackups: 100,
		MaxAge:     28,    // days
		Compress:   false, //Compress确定是否应该使用gzip压缩已旋转的日志文件。默认值是不执行压缩。
	}
	return zapcore.AddSync(infoLumberIO)
}

// 生成故障信息的Writer
func GetErrorWriterSyncer(dir string) zapcore.WriteSyncer {
	//引入第三方库 Lumberjack 加入日志切割功能
	lumberWriteSyncer := &lumberjack.Logger{
		Filename:   dir + "/error.log",
		MaxSize:    10, // megabytes
		MaxBackups: 100,
		MaxAge:     28,    // days
		Compress:   false, //Compress确定是否应该使用gzip压缩已旋转的日志文件。默认值是不执行压缩。
	}
	return zapcore.AddSync(lumberWriteSyncer)
}

/*
例子：

	logger := Logger()
	defer logger.Sync()
	logger.Debugw("调试信息", zap.String("k1", "v1"), zap.Error(errors.New("这是错误信息")))
	logger.Debugf("调试信息%d", 1111)
	logger.Infow("INFO信息", zap.String("k2", "v2"), zap.Error(errors.New("这是错误信息")))
	logger.Errorw("error信息", zap.String("k3", "v3"), zap.Error(errors.New("这是错误信息")))
*/
func Logger() *zap.SugaredLogger {

	level := map[string]zapcore.Level{
		"debug": zapcore.DebugLevel,
		"info":  zapcore.InfoLevel,
		"warn":  zapcore.WarnLevel,
		"error": zapcore.ErrorLevel,
		"fatal": zapcore.FatalLevel,
		"panic": zapcore.PanicLevel,
	}
	p := conf.C().Get("log.savefiledir")
	if p == nil {
		p = "."
	}
	save := conf.C().Get("log.savefile")
	if save == nil {
		save = false
	}
	lev := conf.C().Get("log.loglevel")
	if lev == nil {
		lev = "error"
	}
	encoderfile := GetFileEnCoder()
	encoderconsole := GetConsoleEnCoder()
	infowriter := GetInfoWriterSyncer(p.(string))
	errwriter := GetErrorWriterSyncer(p.(string))

	infolevel := zap.LevelEnablerFunc(func(l zapcore.Level) bool {
		if zap.InfoLevel >= level[lev.(string)] {
			return l < zap.ErrorLevel && l >= level[lev.(string)]
		}
		return l < zap.ErrorLevel && l >= zap.DebugLevel
	})
	errlevel := zap.LevelEnablerFunc(func(l zapcore.Level) bool {
		if level[lev.(string)] >= zap.ErrorLevel {
			return l >= level[lev.(string)]
		}
		return l >= zap.ErrorLevel
	})
	infocore := zapcore.NewCore(encoderfile, infowriter, infolevel)
	errcore := zapcore.NewCore(encoderfile, errwriter, errlevel)
	consolecore := zapcore.NewCore(encoderconsole, zapcore.AddSync(os.Stdout), level[lev.(string)])
	var logger *zap.Logger
	if save.(bool) {
		var core []zapcore.Core
		if level[lev.(string)] >= zap.ErrorLevel {
			core = []zapcore.Core{errcore, consolecore}
		} else {
			core = []zapcore.Core{infocore, errcore, consolecore}
		}
		logger = zap.New(zapcore.NewTee(core...), zap.AddCaller())
	} else {
		logger = zap.New(consolecore, zap.AddCaller())
	}
	return logger.Sugar()
}

var (
	logger *zap.SugaredLogger
)

func L() *zap.SugaredLogger {
	if logger == nil {
		logger = Logger()
	}
	return logger
}
